/*
 *  SyncIT , easy synchronization of files between computers and devices.
 *  Copyright (C) 2011  Christian Masus <cmasus(at)gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version. If redistributing and/or modifying
 *  this file, this notice must be included in the redistributed or
 *  modified copy.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package log;

import java.util.Date;

/**
 * A linked list that works as a queue. It is built up from the end and elements are removed from the top.
 * Elements are added in date order, newest at the end. The oldest element can safely be retrieved from
 * the beginning of the list.
 * @author Christian Masus
 *
 */
public class LogLinkedList {

	private LogMsg first;
	private LogMsg last;
	private int size;

	public LogLinkedList() {
		first = null;
		last = null;
		size = 0;
	}


	public int size() {
		return size;
	}



	/**
	 * Adds an element to the list. Elements with the newest date are put at the end of the list.
	 * Oldest at the beginning of the list.
	 * @param date the date of the element.
	 * @param type the type of the element.
	 * @param message the element message.
	 */
	public void add(Date date, String type, String message) {
		add(new LogMsg(date, type, message));
	}
	/**
	 * Adds an element to the list. Elements with the newest date are put at the end of the list.
	 * Oldest at the beginning of the list.
	 * @param newMsg of type LogMsg.
	 */
	public void add(LogMsg newMsg) {
		if(size <= 0) { // First element in the list
			first = newMsg;
			last = newMsg;
		}
		else if(size == 1) { // Second element in the list
			if( newMsg.getDate().after(first.getDate()) ) {
				last = newMsg;
			}
			else {
				first = newMsg;
			}
			first.setNext(last);
			last.setPrev(first);
		}
		else {
			if( newMsg.getDate().compareTo(last.getDate()) >= 0 ) { //(date.after(last.getDate()) || equals) // New element in the end (normal case)
				last.setNext(newMsg);
				newMsg.setPrev(last);
				last = newMsg;
			}
			else if( newMsg.getDate().before(first.getDate()) ) { // New element at beginning (delayed element)
				first.setPrev(newMsg);
				newMsg.setNext(first);
				first = newMsg;
			}
			else { // New element somewhere in the middle of the list
				LogMsg tmpMsg = last;
				while( newMsg.getDate().before(tmpMsg.getDate()) ) {
					tmpMsg = tmpMsg.getPrev();
				}
				newMsg.setPrev(tmpMsg);
				newMsg.setNext( tmpMsg.getNext() );
				tmpMsg.setNext(newMsg);
				newMsg.getNext().setPrev(newMsg);
			}
		}
		++size;
	}

	/**
	 * Removes the first element from the list (the oldest element) and returns it.
	 * @return a log element as a LogMsg, or null if the list is empty.
	 */
	public LogMsg take() {
		if(size <= 0) {
			size = 0;
			return null;
		}
		else if(size == 1) {
			LogMsg retMsg = first;
			first = null;
			last = null;
			size = 0;
			return retMsg;
		}
		else if(size == 2) {
			LogMsg retMsg = first;
			first = last;
			last.setPrev(null);
			size = 1;
			return retMsg;
		}
		else {
			LogMsg retMsg = first;
			LogMsg second = first.getNext();
			second.setPrev(null);
			first = second;
			--size;
			return retMsg;
		}
	}

	/**
	 * Returns the time of the oldest element in the list. The time of the first element in the list.
	 * @return the time of the oldest element, in the format returned by Date.getTime().
	 */
	public long peekOldestTime() {
		return first.getDate().getTime();
	}



	public String toString() {
		String ret = "size = " + size + "\n";
		LogMsg tmpMsg = first;
		while(tmpMsg != null) {
			ret += tmpMsg.toString() + "\n";
			tmpMsg = tmpMsg.getNext();
		}
		return ret;
	}
}
